home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Mops 2.5 / Mops ƒ / Class < prev    next >
Encoding:
Text File  |  1994-10-03  |  53.9 KB  |  2,091 lines  |  [TEXT/MSET]

  1. \ High-level class/object implementation.
  2.  
  3. \ Note that the object header format is documented at "object building"
  4. \ below.
  5.  
  6. \ June 91    mrh    Moved indexed methods from Object to Indexed-obj in Struct.
  7. \                Added BIND_WITH.
  8. \ May 92    mrh    Added [] as synonym for **
  9. \ Apr 94    mrh    (Mops 2.5) Added several features:
  10. \                Naming of ivars pushing their address.
  11. \                Temp (local) objects
  12. \                record{ ... } replacing general/non-general distinction.
  13. \                classinit: now sent to all superclasses.
  14. \                msg: super> aSuper
  15.  
  16. \ You want documentation?  Here you are!!
  17.  
  18. \ Here are all our various class/object formats:
  19.  
  20.  
  21.  
  22. \            ================= Object header ======================
  23.  
  24. \ Note if the obj is an ivar, it doesn't have a header if it's in a record,
  25. \ unless the ivar is indexed.  Indexed ivars always have headers, no matter
  26. \ what, since the indexing code relies on it.
  27.  
  28.  
  29. \ 2 bytes        Offset to the indexed area, rel to the class pointer
  30. \                (which follows).  If not indexed, this will be 6.
  31.  
  32. \ 4 bytes        Class pointer (relocatable).
  33.  
  34. \ 2 bytes        Offset from the data start to the class pointer.
  35. \                For simple objects (i.e. not embedded), this is -6.
  36. \                For embedded objects, it will be more negative.  Note it
  37. \                will always be negative.
  38.  
  39. \  (object's data starts here)
  40.  
  41. \ For indexed objects, the indexed area (after the ivars) is preceded by
  42. \ the indexed descriptor (xdesc) with this format:
  43.  
  44. \ 2 bytes        Width of indexed elements (in bytes)
  45. \ 4 bytes        Number of elements minus 1 (i.e. LIMIT-1).
  46. \                The low word of this is used by a CHK instruction
  47. \                if #elements is < 32K.
  48.  
  49. \ If indexing is attempted on a non-indexed object, the "offset to the
  50. \ indexed area" will be 6, taking us to the beginning of the object's
  51. \ data.  The CHK instruction will be done at offset -2 from there, which
  52. \ won't be the #elements, of course, but will be the offset to the
  53. \ class pointer WHICH IS ALWAYS NEGATIVE!!  Thus the CHK will always fail!
  54. \ This was a deliberate trick - about the only place in Mops I've
  55. \ resorted to anything like this, you'll be glad to know.
  56.  
  57.  
  58. \        ==============  class dictionary entry  ================
  59.  
  60. \ link/name        as for normal words
  61. \ 4 bytes        call to BLD - the word which builds an object
  62. \ 4 bytes        link to methods chain (relative)
  63. \ 4 bytes        link to ivar chain (relative)
  64. \ 2 bytes        non-indexed data length
  65. \ 2 bytes        width of indexed elements, or zero if not indexed
  66. \ 2 bytes        flags
  67. \ 4(n+1) bytes    N-way to superclasses (n relocatable addrs terminated by zero)
  68.  
  69. \ Flag bits:
  70. \ bit 0            "large" - indexed with > 64K elements.
  71. \ bit 1            class is exported from a module
  72.  
  73.  
  74. \        ==============  ivar dictionary entry  ================
  75.  
  76. \ 4 bytes        hashed name
  77. \ 4 bytes        link to prev ivar dic entry (relative addr)
  78. \ 4 bytes        class pointer (relocatable)
  79. \ 2 bytes        offset of this ivar's data from the base addr of the class
  80. \ 2 bytes        number of elements if indexed, or zero if not
  81. \ 2 bytes        flags
  82.  
  83. \ Flag bits: (zero is rightmost - what will we do on PowerPC?)
  84. \ bit 0            ivar gets an object header
  85.  
  86. \ Note: although indexed objects can have 2^^32 elements, we are
  87. \ assuming that an ivar can't have more than 64K elements.  This is
  88. \ because we are limiting the maximum ivar length of a class to 64K bytes,
  89. \ which is a stricter condition.  Would anybody want a longer ivar than
  90. \ this??
  91.  
  92. \        ==============  method dictionary entry  ================
  93.  
  94. \ 4 bytes        hashed name
  95. \ 4 bytes        link to prev method dic entry (relative addr)
  96. \ 2 bytes        flags
  97.  
  98. \ Flag bits:
  99. \ bit 0            1 = private method
  100.  
  101. \        ==========================================================
  102.  
  103.  
  104. : xx  db ;            \ useful!
  105.  
  106. false    value    PRIVATE?
  107.     0    value    ^CLASS        \ Addr of the class we're currently compiling
  108.     0    value    NEWOBJECT    \ object being created
  109.     0    value    #SUP        \ Number of superclasses for current class
  110.     0    value    SUPERS_TO_SKIP
  111.     0    value    INITID
  112.  
  113.  
  114. \                ===============================
  115.  
  116. \                        UTILITY WORDS
  117.  
  118. \                ===============================
  119.  
  120. : PRIVATE        true  -> private?  ;        \ Turns private methods on.
  121. : PUBLIC        false -> private?  ;        \ Turns them off again.
  122.  
  123. : X    bld  123  ;                \ The 123 blocks optimization!
  124.  
  125. ' x @  forget x      constant    CLASSMK        \  JSR  bldVec-base(A3)
  126.  
  127. : EXBASE    $ 4E92  w,  ;    immediate    \  JSR  (A2)
  128.  
  129. : >OBJ  ( cfa -- ^obj )  inline{ 8 +}  8 +  ;
  130. : OBJ>  ( ^obj -- cfa )  inline{ 8 -}  8 -  ;
  131.             \ Note: we don't use >class here, since obj> shouldn't be
  132.             \ used for embedded objects, and it is used during obj
  133.             \ building when the ^class isn't there yet.
  134.  
  135. : CHKCLASS    \ ( cfa -- cfa )
  136.     class?  ?EXIT
  137.     .id  space  true ?error 80  ;
  138.  
  139. : ?>CLASS   ( ^obj -- ^class )
  140.     >class  dup 0= ?error 81  ;        \ If no legal class ptr, probably
  141.                                     \ not an obj addr at all!
  142.  
  143. \ the following offsets refer to where a ^class points, i.e. the cfa
  144. \ of the class.
  145.  
  146. : MFA    inline{ 4 +}    4 +  ;        \ Methods link
  147. : IFA    inline{ 8 +}    8 +  ;        \ ivar link
  148. : DFA    inline{ 12 +}  12 +  ;        \ Data len (2 bytes),
  149.                                     \  width of indexed elts (2 bytes)
  150. : FFA    inline{ 16 +}  16 +  ;        \ Flags
  151. : SFA    inline{ 18 +}  18 +  ;        \ Superclass N-way pointer
  152.  
  153. : GETDLEN        \ ( ^obj -- n )  Gets length of object's named ivars
  154.     ?>class dfa w@  ;
  155.  
  156. : ^DLEN            \ ( ^obj -- ^datalen )
  157.     ?>class dfa  ;
  158.  
  159. : DLEN&XWID        \ ( ^class -- dlen xwid )
  160.     ?>classInMod
  161.     dfa dup  w@  swap  2+ w@
  162.     ?unHoldMod  ;
  163.  
  164. : DLEN    dlen&xwid  drop  ;
  165. : XWID    dlen&xwid  nip   ;
  166.  
  167.  
  168. : ?>MAINDIC  { ^class -- '^class }
  169.         \ If ^class is exported from a module, we return the main dic
  170.         \ equivalent.  If it's not exported, we return it unchanged.
  171.         \ We need this word since for exported classes, we need to use the
  172.         \ imported address (in the main dictionary) as the class pointer
  173.         \ in a new object or an ivar dic entry (so that the module will be
  174.         \ invoked properly when a method is sent to the object.
  175.  
  176.     ^class ffa 1+ 1 btest
  177.     IF        ^class >name n>count sfind drop
  178.     ELSE    ^class
  179.     THEN  ;
  180.  
  181.  
  182. : FINDM  { selID ^cl -- offs cfa }        \ Finds a method in a class.
  183.     ^cl ?>classInMod -> ^cl
  184.     ^cl -> objClass
  185.     selID ^cl 4 (findm)
  186.     NIF  cr  ^cl .id  108 die  ( method not found )  THEN  ;
  187.  
  188.  
  189. : IVFINDM    \ ( selID ^ivar -- cfa offs )  Looks for a method in an ivar
  190.             \   object.
  191.     8 + @abs ( ^class )  findm  swap  ;
  192.  
  193.  
  194. : SEND  { ^obj selID \ svMB -- }    \  Executes a method given its sel ID.  Used in
  195.                                     \      late binding.  Can also be used if you
  196.                                     \   have a dynamically determined method ID.
  197.     modBase -> svMB
  198.     selID ^obj  objFindM  ex-method
  199.     svMB -> modBase  ;
  200.  
  201.  
  202. : (DEFER)  ( ^obj -- )    \ Looks up SelID at IP and runs the method
  203.     @(ip)  send  ;
  204.  
  205.  
  206. 0 -> quitvec   0 -> abortvec   0 -> objInit        \ clear vectors
  207. ' pfind  -> ufind
  208.  
  209.  
  210. : ?CLASS        \ Error if not compiling a class definition.
  211.     cstate 0=  ?error 115  ;
  212.  
  213.  
  214. \ IVFIND is called when we've parsed a selector.  It determines if the next
  215. \ word is an ivar.
  216. \ Note: if found, (findm) returns the equivalent of the cfa of
  217. \ a method, which for ivars, is the addr of the class pointer.
  218.  
  219. : IVFIND    \ ( str-addr -- offs ^ivar T  |  -- str-addr F )
  220.     cstate  NIF  false  EXIT  THEN
  221.     hash
  222.     ^class  8  (findm)
  223.     IF  8 -  true  ELSE  here false  THEN  ;
  224.  
  225.  
  226. \ TOfind looks for a temp (local) object.
  227.  
  228. : TOfind    \ ( str-addr -- cfa T  |  -- str-addr F )
  229.     tmpObjs  NIF  false  EXIT  THEN
  230.     hash
  231.     tmpObjs  8  (findm)
  232.     IF  8 -  true  ELSE  here  false  THEN  ;
  233.  
  234.  
  235. \ LocFind will be called from Ufind, which is the vector that gets first
  236. \ shot at recognizing a word.
  237. \ LocFind looks at all the possibilities involving local names, which are
  238. \ not in the regular dictionary.  These possibilities are: named parms/locals,
  239. \ local objects, and if a class is being compiled, ivars of this class.
  240.  
  241. \ In the latter case, we arrange for the ivar's address to
  242. \ be pushed at run time simply by compiling ^base followed by an add of the
  243. \ ivar's offset - our code generation will produce optimal code for this.
  244. \ We then have to return the xt of some word to keep FIND happy - we don't
  245. \ need to compile anything else, so we use the xt of NULL and return a 1
  246. \ instead of True - this makes FIND think it's immediate.  So NULL is
  247. \ executed immediately, which does precisely nothing.
  248.  
  249. \ The one exception to this is if the "ivar" turns out to be SELF or SUPER
  250. \ - in this case we need to call the nucleus word SELF which works out
  251. \ the right base address (this is what happened pre-2.5).  Here we keep
  252. \ FIND happy by pushing the xt of SELF and True, so that it sees we've
  253. \ found SELF.
  254.  
  255. : LocFind        \ ( str-addr -- cfa T  |  -- str-addr F )
  256.     Pfind    ?dup  ?EXIT                    \ Found a named parm/local
  257.     TOfind
  258.     IF                                    \ Found local obj
  259.         drop                            \ Don't need its dic addr
  260.         postpone locReg  postpone literal  postpone +
  261.         ['] null  1   EXIT
  262.     THEN
  263.  
  264. \ Now we look for an ivar name
  265.  
  266.     cstate  NIF  false  EXIT  THEN        \ search fails if we're not compiling
  267.                                         \  a class
  268.     dup hash ^class  8  (findm)
  269.     IF                                    \ Found ivar
  270.         drop nip                        \ Don't need its dic addr or str addr
  271.         dup $ FFFE >= IF                \ It's SELF or SUPER
  272.             drop  ['] self  true  EXIT
  273.         THEN
  274.         postpone ^base postpone literal  postpone +
  275.         ['] null  1
  276.     ELSE    false
  277.     THEN  ;
  278.  
  279.  
  280. : ILFA     ( infa -- ilfa )    4+  ;
  281.  
  282.  
  283. : ^ICLASS  ( infa -- ^class | 0 )
  284.     8 + dup @ NIF   drop 0   ELSE   @abs ?>classInMod   THEN  ;
  285.  
  286.  
  287. : IOFFS    ( infa -- ioffs )    12 + w@  ;
  288. : I#ELS    ( infa -- #els )    14 + w@  ;
  289. : IFFA     ( infa -- iffa )    inline{ 16 +}  ;
  290.  
  291.  
  292. : LASTIVAR?        \ ( infa -- infa b )  True if nfa is super or self.
  293.                 \ These are distinguished by having an "offset" of
  294.                 \ $ FFFE and $ FFFF respectively.
  295.     dup @ 0> IF  false  EXIT  THEN
  296.                 \ If there's an Nway for superclasses there, then it can't
  297.                 \  be super or self.
  298.     dup 12 + w@ $ FFFE >=  ;
  299.                 \ Otherwise it's a normal ivar dic entry, so we grab the
  300.                 \  offset field and test it.
  301.  
  302.  
  303. : ^NEXTIVAR    \ ( infa -- infa' )
  304.     ilfa  displace  ;
  305.  
  306.  
  307. forward INITIVAR      \ Performs the classinit: method on the ivar on the stack
  308.  
  309.  
  310. \                        ========================
  311.  
  312. \                                BINDING
  313.  
  314. \                        ========================
  315.  
  316.     0    value    OBJ_BASE
  317.     0    value    OBJ_DISPL
  318.     0    value    OBJ_LOCAL_DISPL
  319.     0    value    OBJ_IND
  320.  
  321. false    value    SELF?
  322.  
  323.  
  324. : OBJ        \ Called from within an inline method.  Passes the object's
  325.             \  base and displacement to Handlers to generate the correct
  326.             \  address.  Optimization will then apply.
  327.  
  328.     obj_base obj_displ
  329.     obj_ind  genaddr
  330.     obj_local_displ  postpone literal  postpone +  ;        immediate
  331.  
  332.  
  333. : IX        \ Also called from within an inline method.
  334.             \ Compiles code to generate the indexed address.
  335.     ^class  dlen&xwid  swap
  336.     self?
  337.     IF  drop  -1  ELSE  6 +  THEN
  338.     obj_base obj_displ  obj_local_displ  obj_ind  ^class ffa w@
  339.     genxaddr  ;            immediate
  340.  
  341.  
  342. local  EARLY_BIND  { oCfa oBase oDispl oLDispl oind slf? -- }
  343.  
  344.  
  345. : INL_BIND    \ ( -- b )
  346.     \ In-line code to be compiled for this method.
  347.     \ But note, we don't do it if obj_base is zero, meaning that
  348.     \ we have put the ^obj in A0 as a temporary.  Some inline
  349.     \ methods could cause a clash on A0.  So in this case we
  350.     \ call the out-of-line code - we return true so that this
  351.     \ will be done by NORM_BIND.  Otherwise we return false.
  352.  
  353.     obj_base
  354.     NIF                                    \ Update cfa to the out-of-line code
  355.         oCfa 2+ dup c@ + aligned  -> oCfa  true
  356.     ELSE
  357.         ^class  cstate  self?                \ Save over upcoming evaluate
  358.         slf? NIF  objClass -> ^class  THEN    \ Set ^class and cstate
  359.         true -> cstate                        \  so ivars are accessible
  360.         slf? -> self?
  361.         oCfa  (compinl)
  362.         -> self?  -> cstate  -> ^class        \ Restore
  363.         false
  364.     THEN  ;
  365.  
  366.  
  367. : NORM_BIND
  368.     oCfa  postpone obj  EB  ;
  369.  
  370.  
  371. :loc  EARLY_BIND        \ { oCfa oBase oDispl oLDispl oind slf? -- }
  372.     obj_base  obj_displ  obj_local_displ  obj_ind        \ Save
  373.     oBase    -> obj_base            oDispl    -> obj_displ
  374.     OLdispl    -> obj_local_displ  oind    -> obj_ind
  375.     oCfa w@  inlMk =
  376.     IF  inl_bind  ELSE  true  THEN
  377.     IF  norm_bind  THEN
  378.     -> obj_ind  -> obj_local_displ
  379.     -> obj_displ  -> obj_base                            \ Restore
  380. ;loc
  381.  
  382.  
  383. : BIND_TO_OBJ        \ ( cfa ^obj -- )
  384.     -1 swap  0  0  false  early_bind  ;
  385.  
  386. : BIND_TO_STK        \ ( cfa -- )
  387.     stkObj  0 swap  false  early_bind  ;
  388.  
  389. : BIND_TO_IVAR  { cfa offs -- }
  390.     cfa  obj_base  obj_displ
  391.     obj_local_displ offs +
  392.     obj_ind  false  early_bind  ;
  393.  
  394. : BIND_TO_TMPOBJ  { cfa offs -- }
  395.     cfa  4  offs
  396.     0 0 false  early_bind  ;
  397.  
  398. : BIND_TO_SELF  { cfa offs -- }
  399.     cfa  obj_base  obj_displ  offs  obj_ind  true  early_bind  ;
  400.  
  401.  
  402. \                    ===========================
  403.  
  404. \                     INITIALIZING NEW OBJECTS
  405.  
  406. \                    ===========================
  407.  
  408.     0    value    ^XDESC        \ Used in the setting up of an index descriptor
  409.     0    value    OFFS        \ Used in setting up ivars
  410. false    value    REC?        \ Are we compiling a record?
  411.  
  412.  
  413. : ?HDRS  { thisClass ^data infa \ xw -- }
  414.         \ For normal ivars, this word sets up the object headers - namely
  415.         \ ^class, ^class offset, xoffs and xdesc.  But if we're in a record,
  416.         \ non-indexed ivars don't have an object header.
  417.         
  418.     thisClass  0EXIT                \ out if self or super
  419.     infa iffa 1+ 0 btest            \ ivar flagged as needing a header?
  420.     0EXIT                            \ out if not
  421.  
  422. \ OK, we need the headers.  Let's set 'em up:
  423.  
  424.     thisClass ?>maindic
  425.     false -> relocChk?
  426.             ^data 6 -  reloc!        \ ^class (safe if outside a module
  427.     true  -> relocChk?                \  here, since ivars of an obj belonging
  428.                                     \  to an exported class can only be
  429.                                     \  accessed while the module is running)
  430.  
  431.     -6        ^data 2-   w!            \ ^class offset
  432.     thisClass xwid -> xw
  433.     xw  NIF                           \ Not indexed:  store dummy xoffs
  434.         6    ^data 8 -  w!  EXIT            \  and we're done.
  435.     THEN
  436.     thisClass dlen aligned            \ Indexed:
  437.     dup  12 +    ^data 8 -    w!            \ xoffs
  438.                 ^data +  -> ^xdesc
  439.     xw                ^xdesc        w!        \ xdesc
  440.     infa i#els  1-    ^xdesc 2+    !  ;    \ #elements
  441.  
  442.  
  443. forward    IVSETUP
  444.  
  445. : NW_IVSETUP  { ^nway boffs EOoffs
  446.                 \ initEOoffs svHeldMod thisClass ^slf totalOffs -- }
  447.  
  448. \ Sets up the groups of ivars for each superclass, for a multiply inherited
  449. \ object.  Each group we call an "embedded object", which sort of describes
  450. \ what it is.
  451. \ ^nway points to the current superclass pointer in the n-way defining the
  452. \ multiple inheritance.  boffs is the base offset from newObject, the actual
  453. \ top-level (non-ivar) object being created.  EOoffs is the extra offset to
  454. \ the current embedded object.  When an embedded object starts at a non-zero
  455. \ EOoffs, we put in front of it a 2-byte offset to the class pointer.  Note
  456. \ that if the multiply inherited object is an ivar, there may not be a class
  457. \ pointer!  This doesn't matter, since it's better for multiply inherited
  458. \ objects to always have the same format, wherever they are, and any attempt
  459. \ to use the class pointer offset to get the (nonexistent) class pointer
  460. \ will most probably be caught by our checks.
  461.  
  462. \ With Mops 2.5 we're now sending classinit: separately to each superclass.
  463.  
  464.     EOoffs -> initEOoffs
  465.     BEGIN
  466.         ^nway @abs ?>classInMod  -> thisClass    \ may hold a mod
  467.         boffs EOoffs + initEOoffs -  -> totalOffs
  468.         thisClass ifa displace  totalOffs  EOoffs  ivSetup
  469.         thisClass -> objClass
  470.         initID  thisClass  4  (findm)              \ ( -- offs cfa T  |  F )
  471.         IF    swap newObject +  totalOffs +  swap  ex-method  THEN
  472.         ?unholdMod                                \ now finished with the mod
  473.         1cell ++> ^nway
  474.         ^nway @
  475.     WHILE        \ another class coming up - store 2-byte ^class offset first
  476.         thisClass dlen  ++> EOoffs
  477.         EOoffs aligned  -> EOoffs
  478.         EOoffs negate 8 -            \ ^class offset for store
  479.         EOoffs initEOoffs -            \ offset not already included in boffs
  480.         boffs + newObject +            \ final addr for store
  481.         w!
  482.         2 ++> EOoffs
  483.     REPEAT  ;
  484.  
  485.  
  486. :f  IVSETUP  { infa boffs EOoffs \ svHeldMod thisClass ^data -- }
  487.  
  488. \ Recursively traverses the tree of nested ivar definitions in a class,
  489. \ building the necessary ^class offsets and indexed area headers.
  490. \ infa is the nfa of the current ivar, and boffs is the current base offset
  491. \ for ivars at this point in the nested ivar structure, relative to newObject,
  492. \ the current top-level object being created.
  493.  
  494. \ When this word is called, if thisClass is in a module, the module will
  495. \ be held.  In some circumstances the caller still needs it.  The
  496. \ recursive call might require another module to be held, so we have to
  497. \ save and restore any module held on entry.
  498.  
  499.     heldMod -> svHeldMod                \ save heldMod
  500.     0 -> heldMod                        \ clear it so nobody can unhold
  501.     BEGIN
  502.         infa @ 0>
  503.         IF                                \ we've hit a superclass n-way
  504.             infa boffs EOoffs NW_ivSetup    \ set up superclasses
  505.             svHeldMod -> heldMod  EXIT    \ restore heldMod, and out
  506.         THEN
  507.         infa lastivar? nip
  508.         IF                                \ no more ivars
  509.             svHeldMod -> heldMod  EXIT    \ restore heldMod, and out
  510.         THEN
  511.  
  512.         infa ^iclass  -> thisClass        \ may hold another mod
  513.         infa ioffs  -> offs                \ relative offs of this ivar
  514.         boffs offs +  newObject +  -> ^data
  515.         
  516.     \ First we do a recursive call to set up the
  517.     \ (nested) ivars of this ivar's class.
  518.     
  519.         ?Rdepth                            \ Check on recursion depth
  520.         infa  ^iclass  ifa  displace    \ infa of last nested ivar
  521.         ( newNfa )  offs boffs +        \ New base offset
  522.         0
  523.         ivSetup                            \ Recursive call to set up this ivar
  524.         ?unHoldMod                        \ unhold any held mod
  525.         thisClass ^data infa  ?hdrs        \ Add headers if nec
  526.         boffs infa  initivar            \ Initialize by calling Classinit:
  527.         infa ^nextivar  -> infa            \ Step to next ivar and loop.
  528.     AGAIN  ;f
  529.  
  530.  
  531. forward  CLASSINIT        \ Will be  classinit: newObject - once we can send
  532.                         \  messages
  533.  
  534.  
  535. \ HASHED-HDR lays down the dic header for an ivar or method.
  536. \ The format is:
  537. \
  538. \ 4 bytes        hash
  539. \ 4 bytes        link (self-relative addr of prev entry)
  540. \
  541. \ This entry has to become the first on the chain, so we pass in the
  542. \ addr of the chain header.
  543.  
  544. : HASHED-HDR        \ ( chain-hdr hash-val -- )
  545.     ,                        \ comma in hash value
  546.     dup displace            \ get abs addr of prev entry
  547.     displ,                    \ comma it in as self-relative addr
  548.     here 8 -  swap  displ!    \ update chain header
  549. ;
  550.  
  551.  
  552. : IVDEF  ( #els ) { iclass \ wid siz clOffs flags -- }
  553.         \ Compiles an ivar dictionary entry.  If indexed, must have
  554.         \ < 64K elements.  iclass is the ivar's class.  The class of
  555.         \ which this is an ivar, is pointed to by ^class.
  556.     
  557.     0 -> flags
  558.     Mword
  559.     ivFind  ?error 117            \ same name as another ivar
  560.     drop
  561.     iclass xwid  -> wid            \ indexed width of ivar class
  562.     iclass dlen  -> siz            \ non-indexed size of this ivar
  563.     ^class dlen  -> clOffs        \ current dLen of new class is
  564.                                 \  initial offset
  565.     ^class  ifa
  566.     here  hash  hashed-hdr        \ Dic header for ivar
  567.  
  568.     iclass ?>mainDic  reloc,
  569.     
  570. \ Now we need to comma in the 2-byte offset to the ivar within
  571. \ the class.  First we need to make some adjustments...
  572. \ Do we need to align the offset:
  573.  
  574.     siz 1 >                \ we do if the ivar size is longer than 1
  575.     wid rec? not and    \ or if it's indexed, and we're not in a record
  576.     or
  577.     IF                \ We do need to align the offset. Note that if the
  578.                     \ ivar class is multiply inherited with >1 superclass
  579.                     \ of non-zero length, the ivar size will always be >1.
  580.         clOffs aligned  -> clOffs
  581.     THEN
  582.     iclass ffa 1+ 2 btest        \ general?
  583. \ &&&    wid  or                        \ or indexed?
  584.     rec? not or                    \ or not in a record?
  585.     IF                            \ Yes. In this case the ivar will have the
  586.                                 \  standard 8-byte object header. So its data
  587.         8 ++> clOffs            \  will start 8 bytes later than otherwise.
  588.         1 -> flags                \ and we'll mark this in the ivar flags
  589.                                 \  so ?hdrs will do the right thing.
  590.     THEN
  591.     clOffs  w,
  592.                     \ Now we need to update the class dLen field by whatever
  593.                     \ we're allocating for this ivar - it will then be the offset
  594.                     \ to the next ivar.   clOffs has the offset so far.
  595.     wid
  596.     IF                \ Indexed. Stack has #els.  We calculate the indexed
  597.                     \ length of this ivar and increment clOffs.
  598.                     \ If we're not in a record, we also need to align the
  599.                     \ non-indexed size of the ivar, since the xdesc must
  600.                     \ be aligned. (If we're in a record, there won't be an
  601.                     \ xdesc.)
  602.         rec? NIF  siz aligned  -> siz  THEN
  603.         dup  w,                        \ Add #els to ivar dic entry
  604.         wid *                        \ Get indexed length
  605.         rec? NIF  6 +  THEN            \ Add 6 for xdesc length
  606.         ++> clOffs                    \ Add to clOffs
  607.     ELSE            \ Not indexed.
  608.         0 w,
  609.     THEN
  610.     flags w,
  611.     siz ++> clOffs                    \ Bump clOffs by non-indexed size of ivar
  612.     clOffs  ^class dfa  w!            \ That's the final value. Replace in dlen.
  613. ;
  614.  
  615. \                    =================================
  616.  
  617. \                            OBJECT BUILDING
  618.  
  619. \                    =================================
  620.  
  621.  
  622. : CL>LEN ( #els ) { theClass \ wid len -- ( #els ) len2 }
  623.                 \ Gets data length of object given #els and class.
  624.     theClass dlen&xwid  -> wid  -> len
  625.     wid IF    ( #els )  dup 32766 >
  626.         IF  theClass ffa 1+ 0 btest 0= ?error 185  then
  627.          dup  wid *  6 +  len +
  628.     ELSE    len
  629.     THEN  ;
  630.  
  631.  
  632. : MAKE_OBJ  ( #els ) { theClass ^obj \ svHeldMod wid len #els -- }
  633.     0 -> #els
  634.     theClass  ?>classinMod  -> theClass
  635.     heldMod -> svHeldMod  0 -> heldMod        \ So dlen&xwid doesn't unhold
  636.     theClass dlen&xwid  -> wid  -> len
  637.     
  638. \ Now if there's an indexed width, we set up xdesc, the indexed descriptor
  639.     
  640.     wid
  641.     IF    -> #els  len aligned -> len
  642.         ^obj len +  -> ^xdesc        \ It's after the ivars, and aligned
  643.         wid  ^xdesc  w!   #els 1-  ^xdesc 2+  !
  644.         len  12 +
  645.     ELSE    6
  646.     THEN
  647.     
  648. \ Now for the object header.
  649.  
  650.     ^obj obj>  w!
  651.     -6  ^obj 2-  w!
  652.     theClass ?>mainDic
  653.     ^obj 6 -
  654.     false -> relocChk?  reloc!        \ obj addr could be in the heap!
  655.     true  -> relocChk?
  656.     ^obj -> newObject
  657.     theClass ifa displace  0  0  ivSetup
  658.     svHeldMod -> heldMod  ?unholdMod
  659.     
  660. \ Lastly we send classinit: to the object.  Note ivSetup has already
  661. \ sent classinit: to each superclass.
  662.  
  663.     classinit  ;
  664.  
  665.  
  666. : DIC-OBJ  ( #els ) { theClass \ ^obj -- }
  667.                 \ Builds an object in the dictionary.
  668.     here >obj -> ^obj                \ Where obj data will start
  669.     theClass  cl>len
  670.     8 +  aligned                    \ Required length
  671.     dup room >  ?error 186            \ "Not enough room"
  672.       reserve                            \ Allocate space for object
  673.     theClass  ^obj  make_obj        \ Set up the object
  674.     align-dp  ;
  675.  
  676.  
  677.     0    value    THECLASS
  678.  
  679.  
  680. :f  BLD        \ ( (#els) -- ) Builds an object.
  681.  
  682.     r>  4-  -> theClass
  683.     cstate
  684.     IF        theClass  ivDef        \ Build an ivar
  685.     ELSE    create_obj            \ Create object header - returns
  686.                                 \  its data address when called
  687.             theClass  dic-obj
  688.     THEN   ;f
  689.  
  690.  
  691. : ]C    true  -> cstate ;        immediate
  692. : C[    false -> cstate ;        immediate
  693.  
  694.  
  695. : HASH,        \ Compiles hashed word for name at here
  696.     @word  hash ,  ;
  697.  
  698.  
  699. \                    ============================
  700.  
  701. \                            :CLASS  etc.
  702.  
  703. \                    ============================
  704.  
  705.  
  706. \ Here we set up some quantities so that we can send messages to SELF
  707. \ or SUPER.  These are treated syntactically as ivars, so to implement
  708. \ them we actually set up dummy ivars SELF and SUPER.
  709.  
  710. \ When we're processing a :CLASS definition, we plug the appropriate
  711. \ addresses into these ivars.  ^SELF is a word defined to return the
  712. \ addr of the dummy ivar SELF, so we can do the plugging.
  713. \ In the case of SUPER, there may be several superclasses, so we have
  714. \ to go through a class descriptor, since that's the only place we look
  715. \ for an n-way (a set of addresses).  So we set the "class" of SUPER
  716. \ to a dummy class SUPCL, which has no ivars or methods (so the search
  717. \ will pass right on by), and plug the superclass pointer of SUPCL to
  718. \ point to the current n-way for the superclasses of the class we're
  719. \ defining.
  720.  
  721.    0    value    (^SELF)
  722.    
  723. : ^SELF  ['] (^self)  displace  ;
  724.  
  725. create    SUPCL                    \ dummy superclass
  726.     classCode  here 2 -  w!
  727.     classMk ,
  728.     0,                            \  methods link - no methods
  729.     0,                            \  ivar link - patched at :CLASS time
  730.  
  731.  
  732. \ META is the super class of Object - top of all inheritance
  733.  
  734. : META    reveal
  735.     [                            \ Note, we're still at the cfa
  736.     drop                        \ Drop the security marker left by colon
  737.     classCode  here 2 -  w!
  738.     classMk ,                    \ class marker goes here
  739.     0,                            \ methods link - none as yet
  740.     0,                            \ ivar link - set to SUPER below
  741.     0,                            \ data len, flags
  742.     0,                            \ super pointer
  743.  
  744. \ Now we set up the SELF and SUPER pseudo-ivars.  We set them up exactly
  745. \ as if they'd been declared as regular ivars in META.
  746.  
  747. create    SUP                        \ this is so we can tick it at SuperRef below.
  748.  
  749.     here                        \ ready for SELF link below
  750.     hash, SUPER
  751.     0,                            \ empty link
  752.     ' supCl  reloc,                \ ^class is dummy supCl (reloc addr reqd)
  753.     $ FFFE  w,                    \ "offset" FFFE means SUPER
  754.  
  755.  
  756.     here
  757.     hash, SELF
  758.     swap  displ,                \ link
  759.     0,                            \ ^class (gets patched at :CLASS time)
  760.     $ FFFF  w,                    \ "offset" FFFF means SELF
  761.  
  762.  
  763. dup    ' (^self)    displ!
  764.     ' meta ifa    displ!
  765.  
  766.  
  767.     0    value    THISM
  768.     0    value    SUPERM
  769. false    value    1SUPER?
  770.  
  771.  
  772. : :CLASS        immediate
  773.     ?exec  header  classCode w,
  774.     here -> ^class
  775.     false -> private?  0 -> #1st  0 -> #last
  776.     307  ;
  777.  
  778.  
  779. : MERGE_INFO  { ^sup ivlen \ ^wid wid prevWid -- dlen }
  780.     ^sup dlen&xwid  -> wid        \ indexed width of this superclass
  781.     ^sup ffa 1+ c@ 5 and        \ Merge "general" and "indexed" flags with
  782.     ^class ffa 1+  cset            \  what we have already
  783.     wid  0EXIT                    \ If this superclass not indexed, we're done
  784.     
  785. \ This class is indexed - we need to check if prev classes were indexed
  786. \  and make sure the widths are compatible.
  787.  
  788.     ^class dfa 2+  -> ^wid        \ Addr of wid field in class we're building
  789.     ^wid w@  -> prevWid            \ Get previous width
  790.     wid 32767 =                    \ "indexed width" of 32767 really means
  791.     IF                            \  obj_array.
  792.         prevWid                    \ In this case if we already have a width,
  793.         IF        prevWid -> wid    \  we use that,
  794.         ELSE    ivlen  -> wid    \ Otherwise current ivar len becomes the width.
  795.         THEN
  796.     THEN
  797.     prevWid
  798.     NIF     wid  ^wid w!        \ If no prev width, set width & we're done
  799.     ELSE    prevWid wid <>  ?error 88        \ "Incompatible indexed widths"
  800.     THEN  ;
  801.  
  802.  
  803. local    (SUP)   { \ ivlen ^nway ^sup thisLen -- }
  804.  
  805. : NEXT_SUPER    ( cfa -- )
  806.     chkClass  -> ^sup
  807.     ^sup reloc,                        \ Add ^class to n-way
  808.     ^sup ivlen merge_info   -> thisLen
  809.     #sup IF                            \ If this is a subsequent class,
  810.         ivlen aligned  2+  -> ivlen    \  align and allow for ^class offset
  811.     THEN
  812.     thisLen ++> ivlen                \ And add ivar length of new class
  813.     1 ++> #sup  ;
  814.  
  815.  
  816. : SUPERS_LOOP
  817.     BEGIN                        \ Loop over superclasses:
  818.         '                        \ cfa of next item on list
  819.         }or)? IF  drop  EXIT  THEN
  820.         ( cfa )  next_super            \ handle next superclass
  821.         1super?  ?EXIT                \ Yerk has only one superclass
  822.     AGAIN  ;
  823.  
  824.  
  825. :loc  (SUP)
  826.     307 ?pairs                        \ Make sure we're in the right place
  827.     classMk ,  14 reserve            \ Space for class record
  828.     here -> ^nway                    \ n-way for superclasses will
  829.     0 -> ivlen  0 -> #sup            \  start here
  830.     ^nway dup 14 -  displ!            \ Point methods link here
  831.     ^nway dup 10 -  displ!            \ and ivars link
  832.     false -> relocChk?
  833.     supers_loop                        \ Loop over superclasses
  834.     0,                                \ Terminate n-way
  835.     ^nway  ['] supCl  mfa  displ!
  836.     ivlen ^class dfa w!                \ Set total ivar length
  837.     ^class  ^self 8 +  reloc!        \ Store ^class in SELF
  838.     true -> relocChk?
  839.     postpone ]c  ( postpone [ )        \ In a class definition
  840.     308
  841. ;loc
  842.  
  843.  
  844. : SUPER{        false -> 1super?   (sup)  ;        immediate
  845. : SUPER(        postpone super{  ;                immediate
  846.  
  847. : <SUPER    true -> 1super?  (sup)    ;            immediate
  848.             \ For compatibility with Yerk -- only looks for 1 superclass
  849.             
  850.             
  851. : (;CL)
  852.     postpone [   postpone c[
  853.     0 ^self 8 + !  ;
  854.  
  855.  
  856. : ;CLASS
  857.     (;cl)  308 ?defn  ;        immediate
  858.  
  859.  
  860.    0    value    DFRSELID
  861. true    value    SLCTRS?        \ Set false to treat selectors as normal words
  862.                             \  for full ANSI compatibility
  863.  
  864. : SEL?        \ ( addr -- addr b )  True if word at addr is a selector xxx:
  865.     slctrs?  NIF  false  EXIT  THEN
  866.     dup  count tuck  1- + c@  & :  =
  867.     swap 1 >  and  ;
  868.  
  869.  
  870. : GETSELECT            \ Gets a selector from the input stream
  871.     mword
  872.     sel?  not ?error 124
  873.     hash
  874.     0 -> dfrSelID  ;
  875.  
  876.  
  877. ' null    vect    GET1ST&LAST
  878. ' null    vect    DoCall1ST
  879. ' null    vect    DoCallLast
  880.  
  881.  
  882. : M_HEADER  { selID -- }    \ Builds a method header and entry sequence.
  883.                             \ Note: also called from the assembler.
  884.     ^class mfa  selID  hashed-hdr        \ Build header
  885.     private? 1 and  w,                    \ plus private flag
  886.     here -> thisM                        \ Remember method cfa
  887.     Mentry  ;                            \ Compile the entry sequence
  888.  
  889.  
  890.  
  891. : :M { \ selID -- }     immediate        \ Start compiling a method.
  892.     true -> method?                        \ Used by Handlers
  893.     ?class  305  0 -> superM
  894.     getSelect -> selID
  895.     10 -> cstate                        \ Means we've read :m, no call_1st yet
  896.     selID ^class 4 (findm)                \ is method already defined?
  897.     IF
  898.         -> superM
  899.         warnings?
  900.         IF    cr  0 -> out
  901.             here count type type# 182             \ "Method redefined"
  902.         THEN
  903.         heldMod 
  904.         NIF  superM ^class > ?error 183  THEN    \ - but if in same class, error
  905.         drop
  906.     THEN
  907.     get1st&last  ?unHoldMod
  908.     selID m_header                        \ Build method header
  909.     #1st #last + IF  thisM 1- 7 bset  THEN
  910.     2 $ 40 + -> obj_base                \ $ 40 indicates A-reg
  911.     0 -> obj_displ                        \ For any inline method calls
  912.     :noname                                \ Start to compile the method
  913.     doCall1st  ;                        \ Compile any Call1st calls first
  914.  
  915.  
  916. : ;M        immediate
  917.     (;)
  918.     #last  IF  true -> method?  doCallLast  defnEnd  false -> method?  THEN
  919.     0 -> #1st  0 -> #last
  920.     305 ?defn  ;
  921.  
  922.  
  923. \    ============== Local sections for methods ==============
  924.  
  925. \ These function just like regular local sections.  The implementation
  926. \ is nearly the same.
  927.  
  928.     0    value    MLOC_ADDR
  929.  
  930.  
  931. : MLOCAL        \ Starts a local section for methods
  932.     local?  ?error 93  1 -> local?        \ We change it to the normal -1
  933.                                         \ as soon as "{" is read.
  934.     postpone :m
  935.     postpone [
  936.     here -> mloc_addr  10 allot        \ Like a forward definition.  We
  937.                                     \ save the addr to patch and leave
  938.                                     \ room for the JMP instrn which will
  939.                                     \ be planted by (patch) below.
  940.     private  ;
  941.  
  942.  
  943. : :MLOC        immediate
  944.     public  ?loc  getSelect drop  95
  945.     here  mloc_addr  (patch)    \ Like :F
  946.     #PL  IF  PLentry  THEN
  947.     false -> local?                \ We do this here so any EXITs
  948.                                 \  tidy everything up properly
  949.     postpone ]  ;
  950.  
  951.  
  952. : ;MLOC        immediate
  953.     (;)  95 ?pairs                \ As local? is now false, everything else
  954.     305 ?defn  ;                \ gets tidied up by (;)
  955.  
  956.  
  957.  
  958. \    ================   INDEXED, GENERAL etc.   =================
  959.  
  960. \ These are words which can appear in a class declaration, in the
  961. \ position
  962.  
  963. \  :class someClass super{ someSuper }   general
  964.  
  965. \ They add attributes to the class.
  966.  
  967.  
  968. : INDEXED        \ ( width -- )  Sets a class and its subclasses to indexed
  969.     ?class  ^class dfa 2+  w!  ;
  970.  
  971. : LARGE        \ Sets the "large" option on an indexed class, allowing
  972.             \ the number of elements to be greater than 32K.
  973.  
  974.     ?class  ^class ffa 1+  0 bset  ;
  975.  
  976.  
  977. : GENERAL    \ Sets the "general" option on a class, which will force an ivar
  978.             \ of that class to be a general object with a class pointer
  979.             \ (so it can be late-bound to) even if it's within a record.
  980.             \ Normally you should just not put such ivars in a record,
  981.             \ but using GENERAL gives a bit of extra security, for classes
  982.             \ for which you know that they will definitely be late-bound
  983.             \ to.  (An attempt to late-bind to an ivar without a class pointer
  984.             \ will give the "not an object" error at run time, which isn't
  985.             \ easy to track down.)
  986.             \ Note that indexed classes are always general anyway.
  987.             \ Also if there's a message sent to [self] somewhere in one of
  988.             \ the methods, we know that the class *must* be general, so
  989.             \ in this case we simply set the general attribute.
  990.  
  991.     ?class  ^class ffa 1+  2 bset  ;
  992.  
  993.  
  994. \                    ===========================
  995.  
  996. \                            SELECTORS
  997.  
  998. \                    ===========================
  999.  
  1000. \ First, here are the special-purpose things which can follow a selector.
  1001. \ These can't appear in isolation.
  1002.  
  1003. \ We allow ** and [] as synonyms of [ ] to late-bind to whatever is on the
  1004. \ stack.  Note:  [] is used in JForth.
  1005.  
  1006. \ We also allow [self] as a synonym of [ self ]
  1007.  
  1008. : **        83 die  ;        \ "Has no meaning unless preceded by a selector"
  1009. : []        83 die  ;
  1010. : [SELF]    83 die  ;
  1011. : SUPER>    83 die  ;
  1012.  
  1013.  
  1014. : ]        immediate
  1015.     hide  dfrSelID  NIF   postpone ]  EXIT  THEN
  1016.     state
  1017.     IF        251 ?pairs  postpone (defer)  dfrSelID ,
  1018.     ELSE    dfrSelID  send
  1019.     THEN
  1020.     0 -> dfrSelID  ;
  1021.  
  1022.  
  1023. : REFTOKEN        \ ( -- cfa tokenType | -- various type )
  1024.                 \ Called when we've parsed a selector - determines type
  1025.                 \  of the following word.
  1026.                 \ The order of checking determines the priority of names.
  1027.                 \ Thus we have to check for locals, then temp objects,
  1028.                 \ then ivars.
  1029.                 \ "various" will be the cfa of whatever came after the selector,
  1030.                 \ or ( offset ^ivar ) for ivars and temp objects (which are
  1031.                 \ treated as ivars of the class Dummy).
  1032.  
  1033.     Mword                                    \ Grab next word
  1034.     Pfind    IF  locTyp        EXIT  THEN        \ check for named parm/locals
  1035.     TOfind    IF  tmpObjTyp    EXIT  THEN        \ check for temp object
  1036.     IVfind    IF  ivarTyp        EXIT  THEN        \ check for ivar
  1037.     
  1038.     ( here )  dup thread dup @ +  (find)  0=  ?error 125
  1039.     dup ['] **        =  IF    lbTyp        EXIT  THEN
  1040.     dup ['] []        =  IF    lbTyp        EXIT  THEN
  1041.     dup ['] [        =  IF    bktTyp        EXIT  THEN
  1042.     dup ['] [self]    =  IF    lbSelfTyp    EXIT  THEN
  1043.     dup ['] super>    =  IF    superTyp    EXIT  THEN
  1044.     dup hdlr
  1045.     CASE
  1046.         wordCode    OF    wordTyp            ENDOF
  1047.         objCode        OF    >obj  objTyp    ENDOF
  1048.         classCode    OF    classTyp        ENDOF
  1049.         -90            OF    classTyp        ENDOF        \ Exported class
  1050.         valCode        OF    valTyp            ENDOF
  1051.         vectCode    OF    wordTyp            ENDOF
  1052.                                 \ Note: here we can treat vectors as words.
  1053.         objPtrCode    OF    objPtrTyp        ENDOF
  1054.  
  1055.         126 die                    \ "That is not an object name"
  1056.     ENDCASE  ;
  1057.  
  1058.  
  1059. \ These words handle the binding of a selector to whatever follows it.
  1060.  
  1061. : IVARREF  { selID offs ^ivar -- }
  1062.     heldMod  0 -> heldMod                \ Save
  1063.     offs  $ FFFE >=  -> selfRef?        \ If self or super.  Allows private
  1064.                                         \ methods to be found by (findm)
  1065.     selfRef?
  1066.     IF  supers_to_skip -> sups2skip  THEN
  1067.                                         \ sups2skip is interrogated by (findm).
  1068.                                         \  This must only be done if self or
  1069.                                         \  super is the target.
  1070.     selID ^ivar ivFindM
  1071.     0 -> sups2skip  0 -> supers_to_skip
  1072.     
  1073.  ( cfa offs-for-ivar )
  1074.     selfRef?
  1075.     IF        bind_to_self  false -> selfRef?
  1076.     ELSE    offs +  bind_to_ivar
  1077.     THEN
  1078.     ?unholdMod  -> heldMod  ;
  1079.  
  1080.  
  1081. : OBJPTRREF  { selID OP-cfa \ ^cl -- }
  1082.     OP-cfa (comp)                    \ Compile a fetch of the OP-cfa,
  1083.                                     \  giving ^obj at run time
  1084.     OP-cfa 4+ @  0= ?error 86        \ "ObjPtr hasn't had a class specified"
  1085.     OP-cfa 4+ @abs  -> ^cl
  1086.     ^cl hdlr -90 =
  1087.     IF                                \ Class is exported
  1088.         ^cl 6 + wdisplace            \ Addr of module
  1089.         compmod =  ?error 84        \ It's the module we're compiling -
  1090.                                     \  this is a no-no, since the ObjPtr
  1091.                                     \  reference will use the OLD module!
  1092.         ^cl  ?>classInMod -> ^cl
  1093.     THEN
  1094.     selID ^cl findm swap  postpone literal  postpone +
  1095.     bind_to_stk  ;
  1096.  
  1097.  
  1098. : TMPOBJREF  { selID offs ^tmpObj -- }
  1099.     heldMod  0 -> heldMod                \ Save
  1100.     selID ^tmpObj ivFindM
  1101.     
  1102.  ( cfa offs-for-tmpObj )
  1103.     offs +  bind_to_tmpObj
  1104.     -> heldMod  ;
  1105.  
  1106.  
  1107. \ SuperRef handles the  msg: super> someSuper  construct.
  1108.  
  1109. : SUPERREF { selID \ ^nway namedClass ^nway' cnt -- }
  1110.     ?class                            \ Must be compiling a class
  1111.     '  -> namedClass                \ get named class xt
  1112.     ^class sfa -> ^nway
  1113.     ^nway -> ^nway'  0 -> cnt
  1114.     BEGIN
  1115.         ^nway' @ 0= ?error 99            \ fix err# ###
  1116.         ^nway' @abs namedClass =
  1117.     NWHILE
  1118.         1cell ++> ^nway'  1 ++> cnt
  1119.     REPEAT
  1120.     cnt -> supers_to_skip
  1121.     selID  $ FFFE  ['] sup  ivarRef        \ equivalent to msg: super
  1122. ;
  1123.  
  1124.  
  1125. \ LBselfRef handles messages to [self] - i.e. late bound to Self.
  1126.  
  1127. : LBSELFREF
  1128.     postpone self  postpone (defer)  ,
  1129.     
  1130.     \ Any class with a late-bound message to self MUST be general.  So if
  1131.     \ we're compling a class (we don't have to be), we'll force it to
  1132.     \ general!
  1133.  
  1134.     cstate IF general THEN  ;
  1135.  
  1136.  
  1137. : COMPDFR    \ (selID cfa -- )
  1138.     (comp)  postpone (defer)  ,  ;
  1139.  
  1140.  
  1141. \ Now here are the main words which compile the selector bindings.
  1142.  
  1143. \ CompRef operates at compile time - it compiles a selector bind.
  1144.  
  1145. : COMPREF        \ ( selID -- )
  1146.     refToken    \ ( selID addr type ) - addr is ^obj for objects, otherwise
  1147.                 \  the cfa of whatever came after the selector.
  1148.     CASE
  1149.         objTyp        OF  objFindM swap  bind_to_obj        ENDOF
  1150.         ivarTyp        OF    ivarRef                            ENDOF
  1151.         objPtrTyp    OF  objPtrRef                        ENDOF
  1152.         tmpObjTyp    OF  tmpObjRef                        ENDOF
  1153.         classTyp    OF    findm
  1154.                         swap  postpone literal  postpone +
  1155.                         bind_to_stk                        ENDOF
  1156.         valTyp        OF  compdfr                            ENDOF
  1157.         locTyp        OF  compdfr                            ENDOF
  1158.         wordTyp        OF  compdfr                            ENDOF
  1159.         lbTyp        OF  drop  postpone (defer)  ,        ENDOF
  1160.         lbSelfTyp    OF  drop  LBselfRef                    ENDOF
  1161.         bktTyp        OF  drop  -> dfrSelID  251            ENDOF
  1162.         superTyp    OF    drop  superRef                    ENDOF
  1163.  
  1164.         82 die                        \ "Selector can't be used on that"
  1165.         
  1166.     ENDCASE  ;
  1167.  
  1168.  
  1169. \ RunRef is the execution mode equivalent - it executes a selector bind.
  1170.  
  1171. : RUNREF    \ ( selID -- )
  1172.     refToken
  1173.     ( selID addr type )
  1174.     CASE
  1175.         notFnd        OF  abort                    ENDOF
  1176.         objTyp        OF  objFindM                 ENDOF
  1177.         classTyp    OF  findm  >r + r>            ENDOF
  1178.         valTyp        OF  @  objFindM                ENDOF
  1179.         objPtrTyp    OF  @  objFindM                ENDOF
  1180.         wordTyp        OF  execute  objFindM        ENDOF
  1181.         lbTyp        OF  drop   swap objFindM    ENDOF
  1182.         bktTyp        OF  drop -> dfrSelID
  1183.                         here  ['] null            ENDOF
  1184.         82 die                        \ "Selector can't be used on that"
  1185.     ENDCASE
  1186.     ex-method  ;
  1187.  
  1188.  
  1189. \                ======== Selector support =========
  1190.  
  1191.  
  1192. \ MESSAGE is the handling word invoked by using a selector.
  1193.  
  1194. : MESSAGE        immediate
  1195.     state
  1196.     IF                      \ Compile state
  1197.         compRef                \ Compile the message send
  1198.         ?unHoldMod
  1199.     ELSE
  1200.         runRef                \ Run state - execute object/vector reference.
  1201.                             \ ?unHoldMod is called by ex-method at the
  1202.                             \ end, so we don't need to call it here.
  1203.     THEN  ;
  1204.  
  1205.  
  1206. \ 1stFind lumps together all the special cases we have to look for after
  1207. \ we've parsed an input word, but before we can do a regular dictionary
  1208. \ lookup.  At present these are selectors, named parms/locals, ivars
  1209. \ and local objects.  If we invent more later, they can easily be added.
  1210. \ The vector Ufind is then set to this word so it is called before the
  1211. \ regular dictionary search.  If we succeed here, we return the selector
  1212. \ ID or zero, the cfa of the handling word, and 1 or -1 (this will cause
  1213. \ FIND to exit without doing anything more).  If we fail, we return the
  1214. \ original string address and false.
  1215.  
  1216. : 1stFIND    \ ( str-addr -- selID message-cfa T  |  -- str-addr F )
  1217.     sel?                        \ is it a selector?
  1218.     IF        hash                \ yes - leave selID
  1219.             ['] message  1        \  and cfa of message, and 1 (it's immediate)
  1220.     ELSE    LocFind                \ no - look for the various kinds of local name
  1221.     THEN  ;
  1222.  
  1223.  
  1224. ' 1stFind -> Ufind
  1225.  
  1226.  
  1227. : OBJLEN    \ ( -- objlen )  Computes total data length of current object.
  1228.  
  1229.     ^base ^dlen  dup w@  swap 2+ w@  ?dup
  1230.     IF  idxBase 4- @ 1+  *  + 4+  THEN   ;
  1231.  
  1232.  
  1233. :f CLASSINIT    classinit: newObject  ;f
  1234.  
  1235. getSelect classinit:  -> initID
  1236.  
  1237.  
  1238. :f INITIVAR  { boffs infa -- }
  1239.     infa  ^iclass  0EXIT                \ Don't init self or super
  1240.     initID  infa  ivFindM  drop
  1241.     infa  ioffs boffs +  newObject +    \ ( cfa ^data )
  1242.     swap  ex-method  ;f                    \ execute ClassInit:
  1243.  
  1244. forward DUMP
  1245.  
  1246.  
  1247. \ SET_CLASS is a utility word used to patch nucleus objects when their classes
  1248. \ are defined in higher-level files.  Actually it could be used to change the
  1249. \ class of any object, if anyone is silly enough to want to do that.
  1250.  
  1251. \ Usage:  fFcb  ['] file  set_class
  1252.  
  1253. : SET_CLASS  { ^obj theClass -- }
  1254.     theClass  chkClass  ^obj 6 -  reloc!        \ Patch ^class
  1255.     6  ^obj 8 -  w!                    \ Not indexed (yet)
  1256.     -6 ^obj  2-  w!  ;                \ ^class offset
  1257.  
  1258.  
  1259. : CHKSAME        \ ( ^obj -- ^obj )
  1260.         \ A check that two objects are of exactly the
  1261.         \ same class.
  1262.     dup >classCfa  ^base >classCfa  <> ?error 87  ;
  1263.  
  1264.  
  1265. \            ========= Object pointers ==========
  1266.  
  1267. \ Object pointers are low-level objects (like VALUEs) which point to a
  1268. \ normal (high-level) object, and which allow early-bound messages to be
  1269. \ sent to the object by syntactically sending them to the object pointer.
  1270.  
  1271. \ The normal syntax is
  1272.  
  1273. \  ObjPtr  ZZZ    class_is  someClass
  1274.  
  1275. \ Thereafter, any messages sent to zzz are early-bound to the object that
  1276. \ zzz points to at the time the message executes.
  1277.  
  1278. \ If you need to declare the object pointer before the class exists, use
  1279. \ SET_TO_CLASS once the class is defined, thus:
  1280. \
  1281. \ :class  SOMECLASS    super{ object }
  1282. \
  1283. \    ' someOP  set_to_class  someClass
  1284. \
  1285. \    etc.
  1286.  
  1287. : (ToOP)  { ^obj OPcfa \ OPcl -- }
  1288.  
  1289.     ^obj  nilP =                \ If we're storing nil, anything goes
  1290.     NIF    OPcfa 4+ @abs  -> OPcl
  1291.         ^obj 6 - @abs  OPcl  <>
  1292.         IF                      \ Mismatch. We give some useful(?) info.
  1293.             cr  ^obj obj> .id ."  -> "  OPcfa .id
  1294.             87 die
  1295.         THEN
  1296.     THEN
  1297.     ^obj OPcfa !  ;
  1298.  
  1299.  
  1300. :f  ToObjPtr
  1301.     state
  1302.     IF  lit-addr  postpone (toOP)  ELSE  (toOP)  THEN  ;f
  1303.  
  1304.  
  1305. : CLASS_IS    \ ( --< class > )
  1306.     ?exec  '  chkClass  here 4-  reloc!  ;
  1307.  
  1308.  
  1309. : SET_TO_CLASS  { ^objPtr \ ^cl --< class > }
  1310.     '  -> ^cl
  1311.     ^objPtr hdlr -62 <> ?error 85        \ "That isn't an ObjPtr"
  1312.  
  1313.             \ Now if "class" is an imported word, we change the handler code
  1314.             \ to "imported class".  This is normally done when the module
  1315.             \ is compiled, but it may not be yet, since we probably
  1316.             \ want to refer to the ObjPtr in the module.
  1317.  
  1318.     ^cl hdlr -92 = if  -90 ^cl 2- w!  else  ^cl chkClass drop  then
  1319.     ^cl  ^objPtr 4+  reloc!  ;
  1320.  
  1321.  
  1322. \ If you are late-binding in a loop, it can be much faster if you do the bind
  1323. \ just once, then reuse the resulting cfa each time in the loop.  This way
  1324. \ you only have to perform the method search once.  To bind initially and get
  1325. \ the cfa, use
  1326.  
  1327. \  BIND_WITH ( ^obj --<selector> ^obj-modified  cfa )
  1328.  
  1329. \ Usage:  (saveCfa and ^obj-mod are values or locals)
  1330.  
  1331. \    (get object's address)  bind_with someSelector:  -> saveCfa  -> ^obj-mod
  1332.  
  1333. \    (in the loop)  ^obj-mod  saveCfa  ex-method
  1334.  
  1335. \ The use of the modified object address is a bit obscure, and is related to
  1336. \ multiple inheritance.  The method you actually end up binding to may be in
  1337. \ one of the superclasses, and the ivars for that superclass may not start at
  1338. \ the beginning of the object.  The modified object address is the start of
  1339. \ the ivars for the superclass, which is the address the method needs.
  1340.  
  1341. \ Note also that the method may turn out to be in a module, so when you have
  1342. \ finished you should put ?unHoldMod to free up the module.
  1343.  
  1344. : (BWITH)         \ ( ^obj selID -- ^obj-modified  cfa )
  1345.     over  ?>class  findm  >r  +  r>  ;
  1346.  
  1347. : BIND_WITH        \ ( ^obj --<selector> ^obj-modified  cfa )
  1348.     getSelect  postpone literal
  1349.     postpone (bwith)  ;        immediate
  1350.  
  1351.  
  1352. \        ===================================
  1353.  
  1354. :class    OBJECT    super{ meta }
  1355.  
  1356. :m CLASS:    ^base ?>class ?>classinMod  ;m
  1357.  
  1358. :m .ID:        ^base obj>  .id  ;m
  1359.  
  1360. :m .CLASS:    ^base >classCfa  .id  ;m
  1361.  
  1362. :m ADDR:    inline{ obj}
  1363.         ^base  ;m
  1364.  
  1365. :m ABS:        ^base  ;m        \ Included for Neon/Yerk compatibility
  1366.  
  1367. :m LENGTH:    \ ( -- len )  Gets total length of object.
  1368.     objlen  ;m
  1369.  
  1370.  
  1371. :m COPYTO:    \ ( ^obj -- )  Copies the ivar part of the passed in object
  1372.             \ to self.  Doesn't check type - be careful.
  1373.     ^base  dup ^dlen w@  aligned_move  ;m
  1374.  
  1375. \    The following methods need to be defined for all objects.
  1376. \    We give them their default definitions here.
  1377.  
  1378. :m CLASSINIT:  ;m    \ Our standard constructor method.  Called automatically
  1379.                     \ whenever an object is created.
  1380.  
  1381. :m DEEP_CLASSINIT:    \ Also does classinit: on all nested ivars.  Use for
  1382.                     \  totally (re-)initializing an object.
  1383.     ^base -> newObject
  1384.     class: self ifa displace  0  0
  1385.     ivSetup  ?unholdMod  ;m
  1386.  
  1387.  
  1388. \ RELEASE: is our standard destructor method.  Any objects that
  1389. \ allocate heap storage will redefine this appropriately.
  1390. \ Our convention is that an object will release ALL its
  1391. \ storage when it gets a release: message. Other methods
  1392. \ can be provided to partly release storage, as needed.
  1393.  
  1394. :m RELEASE:    inline{ }  ;m
  1395.  
  1396.  
  1397. :m DUMP:
  1398.     .id: self  ."  class: "  .class: self
  1399.     ^base  objlen  dump  ;m
  1400.  
  1401. :m PRINT:        \ Used for a formatted display, if appropriate.
  1402.                 \ Default is just a dump.
  1403.     dump: self  ;m
  1404.  
  1405. ;class
  1406.  
  1407.  
  1408. \ Bytes is used as the allocation primitive for basic classes
  1409.  
  1410. : BYTES  { numBytes \ svRec? -- }
  1411.     ?class
  1412.     rec? -> svRec?  true -> rec?    \ Don't want an object header here
  1413.     ['] object ivDef
  1414.     numBytes  ^class dfa  w+!
  1415.     svRec? -> rec?  ;
  1416.  
  1417.  
  1418.  
  1419. (*        ===================  Local objects  ======================
  1420.  
  1421. Syntax:
  1422.  
  1423. : aWord  { loc1 loc2 -- }        \ Locals are optional, of course
  1424.     temp
  1425.     {    var        v1
  1426.         int        i1
  1427.         string    s
  1428.     }
  1429.  
  1430.  Or you can use temp{ ...  }temp if you prefer.
  1431.  
  1432. As the syntax is quite similar to a list of ivars of a class, we actually
  1433. implement the temp objects as though they're the ivars of a dummy class
  1434. (which we uncreatively call Dummy).  This is just a convenience during
  1435. the compilation of a defn with temp objects.  It allows us to define them
  1436. and keep them visible during the compilation of the definition, while mainly
  1437. using existing code for ivar access.  We don't need these ivar dic entries
  1438. once the defn is finished, so we actually put them high in the dictionary
  1439. out of the way of the defn we're compiling.  At the end of the defn,
  1440. we reinitialize Dummy's ivar link ready for next time.
  1441. *)
  1442.  
  1443. getSelect release:            constant    releaseID
  1444.  
  1445.  
  1446. :class DUMMY  super{ object }
  1447. ;class
  1448.  
  1449. ' dummy ifa @    constant    dummyIfa
  1450.  
  1451. : RESETTEMPS    dummyIfa  ['] dummy ifa  !  ;
  1452.     \ Note we don't have to worry about the mfa since Dummy never gets
  1453.     \ its own methods.
  1454.  
  1455.  
  1456. (*
  1457. InitTemps is called when we're compiling the prologue for a definition
  1458. with temp objects.  It compiles a call to make_obj for each object, so
  1459. that they're properly initialized.  Note we can't just call make_obj once
  1460. using class Dummy, since its ivar list is wiped out after each defn
  1461. with temp objects, so at run time it won't have any!  But we don't need
  1462. Dummy at run time anyway - we only need the "ivars" which are the
  1463. temp objects themselves.
  1464. *)
  1465.  
  1466. : 1TEMP  ( ^iclass ioffs -- )
  1467.     locReg +  make_obj  ;
  1468.     
  1469.  
  1470. :f INITTEMPS  { \ infa -- }
  1471.     ['] dummy ifa displace  -> infa
  1472.     BEGIN
  1473.         infa @ 0<
  1474.     WHILE
  1475.         infa ^iclass  lit-addr
  1476.         infa ioffs  postpone literal
  1477.         postpone 1temp
  1478.         infa ^nextivar  -> infa
  1479.     REPEAT  ;f
  1480.  
  1481. (*
  1482. ReleaseTemps is called back from Handlers when it's compiling an exit.
  1483. It compiles a release: xxx for all temp objects.  Because of the way
  1484. we've defined release: in class Object, for simple objects no code will
  1485. actually be generated.  
  1486.  
  1487. Note we mustn't call resetTemps here since this might be an EXIT, not
  1488. the final semicolon.  We leave calling resetTemps till a new temp{ comes
  1489. up.
  1490. *)
  1491.  
  1492. : RELEASETEMPS  { \ infa -- }
  1493.     ['] dummy ifa displace  -> infa
  1494.     BEGIN
  1495.         infa @ 0<
  1496.     WHILE
  1497.         infa  ^iclass  0EXIT            \ shouldn't happen, actually
  1498.         releaseID  infa  ivFindM drop
  1499.         infa ioffs bind_to_tmpObj        \ compile release:
  1500.         infa ^nextivar  -> infa
  1501.     REPEAT
  1502. ;
  1503.  
  1504.  
  1505. : }TEMP
  1506.     130 ?pairs
  1507.     ['] } !                                \ restore old action for "}"
  1508.     -> ^class  -> state  -> cstate  -> DP    \ restore other things
  1509.     tmpObjs dlen 8 +  -> frameSize        \ work out frame size
  1510.     local? NIF                            \ compile prologue unless we're in
  1511.         PLentry  initTemps                \  a local section (then it gets done
  1512.     THEN                                \  by :LOC)
  1513.     ['] releaseTemps -> relTmps            \ for Handlers callback at exit time
  1514. ;
  1515.  
  1516.  
  1517. : TEMP{        immediate
  1518.  
  1519. (*    First we have to allocate an internal local variable as a frame pointer.
  1520.     There are 4 situations.  There may or may not already be locals, and
  1521.     we may or may not be in a local section.  Note we can be in a local
  1522.     section even if there aren't already locals, since the purpose of the
  1523.     local section might be just to establish a section for these temp objects.
  1524.  
  1525.     If there are already locals, we just add another.  If we're not in a
  1526.     local section we need to recompile the entry sequence (done by PLentry)
  1527.     since the number of regs to be saved and set up is different.  But if
  1528.     we're in a local section, we don't have to recompile since we haven't
  1529.     called PLentry yet, so we just add the extra local.  If there aren't any
  1530.     locals already, we just call initLocs which sets them up, before adding
  1531.     the new one.
  1532. *)
  1533.     resetTemps
  1534.     #PL IF
  1535.         local?    NIF        PLentry_addr -> DP  THEN
  1536.     ELSE
  1537.         initLocs                \ No locs before, so set up for them now
  1538.     THEN
  1539.     local? IF  -1 -> local?  THEN    \ If in a local section, setting local?
  1540.                                     \ to -1 means we've defined the locals
  1541.                                     \ so can't do it again
  1542.     " x " here place  here addToParmList
  1543.  
  1544. (*    next we save DP and move halfway up in the free dic space - we'll put
  1545.     the "ivar dic entries" for the temp objs there - we don't need them
  1546.     after the defn is compiled.
  1547. *)
  1548.     here            room 2/ ++> DP  align-dp
  1549.     cstate            true -> cstate
  1550.     state
  1551.     ^class
  1552.     ['] } @                        \ save old action for "}"
  1553.     ['] }temp  -> }                \ "}" will now be same as }temp
  1554.     130                            \ for ?pairs
  1555.  
  1556.     ['] dummy dup    -> ^class    \ local objs will look like ivars of Dummy
  1557.                     -> tmpObjs    \ this will enable finding them
  1558.     
  1559.  
  1560.  
  1561.     postpone [                    \ stop compiling
  1562. ;
  1563.  
  1564.                             
  1565. : TEMP        gobble{  postpone temp{  ;        immediate
  1566.  
  1567.  
  1568. (*        ====================  Records  ========================
  1569. Syntax:
  1570.  
  1571.     record <name>        \ The name is optional
  1572.    {    var        v1
  1573.         int        i1
  1574.         string    s
  1575.    }
  1576.  
  1577. Or you can use record{ ...  }record if you prefer, if it's unnamed.
  1578. The similarity of syntax to temp objects is quite deliberate.
  1579. *)
  1580.  
  1581. : }RECORD
  1582.     131 ?pairs
  1583.     ['] } !                        \ restore old action for "}"
  1584.     false -> rec?  ;
  1585.  
  1586. : RECORD{
  1587.     ?class                        \ must be compiling a class
  1588.     ['] } @                        \ save old action for "}"
  1589.     ['] }record  -> }            \ "}" will now be same as }record
  1590.     131                            \ for ?pairs
  1591.     true -> rec?  ;
  1592.  
  1593.  
  1594. : RECORD  { \ sv_>in sv_^class -- }
  1595.     >in @ -> sv_>in ^class -> sv_^class
  1596.     Mword  count  " {" s=
  1597.     NIF            \ It's a name for the record
  1598.         true -> rec?
  1599.         sv_>in  >in !
  1600.         ['] object  ivDef
  1601.         sv_^class -> ^class
  1602.         gobble{                    \ "{" must follow
  1603.     THEN
  1604.     record{  ;
  1605.  
  1606.  
  1607. \ CL1 is our first cleanup word - called on an abort.  Resets things
  1608. \  to normal.  Later cleanup words do their special stuff, then call CL1.
  1609.  
  1610. : CL1        (;cl)  clrComp  ['] (}) -> }
  1611.             resetTemps  false -> rec?
  1612.             0 -> extraFind  ;
  1613.  
  1614. ' cl1  -> abortVec
  1615.  
  1616.  
  1617. <" Struct
  1618.  
  1619. (* Normally we don't get here.  In order to do various tests on classes,
  1620.  we comment out the  <" Struct  and run various parts of the torture test
  1621.  stuff following.
  1622. *)
  1623.  
  1624. +echo
  1625.  
  1626. :class    VAR    super{ object }
  1627.  
  1628.     4 bytes data
  1629.  
  1630. :m CLEAR:
  1631.     inline{ 0 obj !}
  1632.     0 ^base !  ;m
  1633.  
  1634. :m GET:
  1635.     inline{ obj @}
  1636.     ^base @  ;m
  1637.  
  1638. :m PUT:
  1639.     inline{ obj !}
  1640.     ^base !  ;m
  1641.  
  1642. :m GETT:    ^base @  ;m
  1643.     
  1644. :m PUTT:    ^base !  ;m
  1645.  
  1646. :m +:
  1647.     inline{ obj +!}
  1648.     ^base +!  ;m
  1649. :m -:
  1650.     inline{ obj -!}
  1651.     ^base -!  ;m
  1652. :m ->:
  1653.     inline{ @ obj !}
  1654.     chksame  get: var  put: self  ;m
  1655.  
  1656. :m TEST:        db  ;m
  1657.  
  1658. mlocal LOCTEST:  { aa \ bb cc -- }
  1659.  
  1660. :m AAA:    aa -> bb ;m
  1661.  
  1662. :mloc  LOCTEST:
  1663.     db  aaa: self  cc -> bb  1234 drop ;mloc
  1664.  
  1665.  
  1666. :m  PRINT:
  1667.     ^base @  .  ;m
  1668.  
  1669. :m CLASSINIT:    $ 123  put: self  ;m
  1670.  
  1671. ;class
  1672.  
  1673. :class    BYTE    super(  object  )
  1674.  
  1675.     1 bytes data
  1676.  
  1677. :m CLEAR:
  1678.     inline{ 0 obj c!}
  1679.     0 ^base c!  ;m
  1680.  
  1681. :m GET:
  1682.     inline{ obj c@x}
  1683.     ^base c@x  ;m
  1684.  
  1685. :m UGET:
  1686.     inline{ obj c@}
  1687.     ^base c@  ;m
  1688.  
  1689. :m PUT:
  1690.     inline{ obj c!}
  1691.     ^base c!  ;m
  1692.  
  1693. :m ->:
  1694.     inline{ c@ obj c!}
  1695.     chksame  c@  put: self  ;m
  1696.  
  1697. :m PRINT:
  1698.     ^base c@  .        ;m
  1699.  
  1700. :m CLASSINIT:    9 put: self  ;m
  1701.  
  1702. ;class
  1703.  
  1704. :class    BOOL    super(  byte  )
  1705.  
  1706. :m GET:
  1707.     inline{ obj c@x}
  1708.     ^base c@x  ;m
  1709.  
  1710. :m PUT:
  1711.     inline{ 0<> obj c!}
  1712.     0<>  ^base c!  ;m
  1713.  
  1714. :m SET:
  1715.     inline{ true obj c!}
  1716.     true ^base c!  ;m
  1717.  
  1718. :m PRINT:
  1719.     get: self  IF  ." true"  ELSE  ." false"  THEN  ;m
  1720.  
  1721. :m CLASSINIT:    clear: self  ;m
  1722.  
  1723. ;class
  1724.  
  1725.  
  1726. :class    BARRAY  super{ object }  1 indexed
  1727.  
  1728. :m  AT:        \ ( index -- n )
  1729.     inline{ ix c@}
  1730.     ^elem1  c@  ;m
  1731.  
  1732. :m  TO:        \ ( n index -- )
  1733.     inline{ ix c!}
  1734.     ^elem1  c!  ;m
  1735.  
  1736.  
  1737. :m ^ELEM:    \ ( index -- addr )
  1738.     inline{ ix}
  1739.     ^elem1  ;m
  1740.  
  1741. :m FILL:    \ ( value -- )  Fills all elements with value.
  1742.     idxbase  limit 2*  bounds
  1743.     ?DO  dup  i c!  LOOP  drop  ;m
  1744.  
  1745. :m WIDTH:    1  ;m        \ Faster than the default in Object
  1746.  
  1747. :m GETELEM:    \ ( addr -- n )  Fetches one element at addr
  1748.     c@x  ;m
  1749.  
  1750. ;class
  1751.  
  1752.  
  1753. \ Testing record{
  1754.  
  1755. :class VAR+ super{ var }
  1756.  
  1757. :m QQ:    get: [self]  ;m        \ should make class general
  1758.  
  1759. ;class
  1760.  
  1761.  
  1762. :class RECTEST super{ object }
  1763.  
  1764.     var    vv
  1765.  
  1766.     record RR
  1767.     {        var        v1
  1768.             bool    b1
  1769.         3    barray  bbb
  1770.             byte    b2
  1771.             var        v2
  1772.             var+     v3
  1773.     }record
  1774.     
  1775. :m TEST:
  1776.     db  get: v1  put: b1  bbb  b2 self
  1777. ;m
  1778.  
  1779. ;class
  1780.  
  1781. recTest rrr
  1782. test: rrr
  1783. key!
  1784.  
  1785.  
  1786. \ Testing temp objects
  1787.  
  1788. : q db
  1789. temp
  1790. {    var    v1
  1791.      var    v2
  1792. }temp
  1793.     v1 v2
  1794.     get: v1  get: v2 db ;
  1795.  
  1796. key!
  1797.  
  1798.  
  1799. :class INT  super( object )
  1800.  
  1801.     2    bytes    data
  1802.  
  1803. :m CLEAR:
  1804.     inline{  0 obj !  }
  1805.     0 ^base !  ;m
  1806.  
  1807. :m UGET:
  1808.     inline{  obj w@  }
  1809.     ^base w@  ;m
  1810.  
  1811. :m GET:
  1812.     inline{  obj w@x  }
  1813.     ^base w@x  ;m
  1814.  
  1815. :m IPUT:    ^base w!  ;m
  1816.  
  1817. :m DISP:
  1818.     inline{  obj 2+ @  }  ;m
  1819.  
  1820. :m PUT:
  1821.     inline{  obj w!  }
  1822.     ^base  w!  ;m
  1823.  
  1824. :m MOVE:
  1825.     inline{  obj 4+ w@  obj w!  }  ;m
  1826.  
  1827.  
  1828. :m +:    inline{  obj w+!  }
  1829.     ^base  w+!  ;m
  1830.  
  1831. :m ->:
  1832.     inline{  w@ obj w!  }
  1833.     db  chksame  1234 drop  get: int  put: self  ;m
  1834.  
  1835. :m ++>:
  1836.     inline{  w@ obj w+!  }
  1837.     db  chksame  uget: int  +: self  ;m
  1838.  
  1839. :m .ID:    ." haha"  ;m
  1840.  
  1841. :m TEST:
  1842.     1234 drop  .id: super  ;m
  1843.  
  1844. :m CLASSINIT:    db  $ 456 put: self  ;m
  1845.  
  1846. ;class
  1847.  
  1848.  
  1849. :class CC  super{ byte int var bool }
  1850.  
  1851. :m TEST:
  1852.     db  uget: self        \ offs should be 0
  1853.     +: self                \ offs should be 4
  1854.     set: self  ;m        \ offs should be A
  1855.  
  1856. :m TEST1:
  1857.     db  set: self
  1858.     get: super> bool    \ should get -1
  1859.     get: super
  1860. ;m
  1861.     
  1862. :m classinit:  db  ;m
  1863.  
  1864. ;class
  1865.  
  1866. cc CCC
  1867.  
  1868. key!
  1869.  
  1870.  
  1871. :class STRANGE  super{ object }
  1872.     var VV
  1873.     byte BB
  1874. :m GET:  get: vv  get: bb  ;m
  1875. :m PUT:  put: bb  put: vv  ;m
  1876.  
  1877. ;class
  1878.  
  1879.  
  1880. :class    ARRAY    super(  object  )    4 indexed
  1881.  
  1882. \ 8 bytes data        \ Comment out to check collapsing of embedded objs
  1883.  
  1884. :m ^ELEM:    \ ( index -- addr )
  1885.     ^elem4  ;m
  1886.  
  1887. :m QQQ:    inline{ ix }  ;m
  1888.  
  1889. :m  AT:        \ ( index -- n )
  1890.     inline{ ix @ }
  1891.     ^elem4  @  ;m
  1892.  
  1893. :m  ATT:    ^elem  @  ;m        \ As for AT:, but not inline
  1894.                 \  and uses unoptimized ^elem
  1895.  
  1896. :m  TO:        \ ( n index -- )
  1897.     inline{  ix !  }
  1898.     ^elem4  !  ;m
  1899.  
  1900. :m  +TO:        \ ( n index -- )
  1901.     inline{ ix +! }
  1902.     ^elem4  +!  ;m
  1903.  
  1904. :m -TO:        \ ( n index -- )
  1905.     inline{ ix -! }
  1906.     ^elem4  -!  ;m
  1907.  
  1908. :m FILL:        \ ( value -- )  Fills all elements with value.
  1909.     idxbase  limit 4*  bounds
  1910.     DO  dup  i !  4 +LOOP  drop  ;m
  1911.  
  1912. :m EXEC:        \ ( index -- )  execute the cfa, by jumping there.
  1913.     inline{ ix ex}
  1914.     ^elem: self  execute  ;m
  1915.  
  1916. :m TEST:
  1917.     exec: self  ;m
  1918.  
  1919. :m ATEST:
  1920.     1 at: self  ;m
  1921.  
  1922. ;class
  1923.  
  1924. var VV
  1925.  
  1926. :class XXX super( object )
  1927.     var    VV1
  1928.     var    VV2
  1929. 3    array    AA
  1930.  
  1931. :m TEST:     inline{ 9 putt: vv2 get: vv2 at: aa}  get: vv2 ;m
  1932. :m TESTT:    db  2 at: aa  get: vv1  get: vv2  ;m
  1933. :m ZZ:        inline{ get: vv2 get: vv}  get: vv2  ;m
  1934.  
  1935. :m  CLASSINIT:        3 0 do  $ 777  i  to: aa   loop  ;m
  1936. ;class
  1937.  
  1938. :class    YYY    super{ xxx }
  1939. ;class
  1940.  
  1941. :class    ZZZ    super{ object }
  1942.     xxx    X1
  1943.     yyy    Y1
  1944. :m TEST: db  ;m
  1945. ;class
  1946. zzz    Z1
  1947.  
  1948. :class    QQQ  super( object )
  1949.     xxx    XXX1
  1950.     xxx    XXX2
  1951. :m TEST:  zz: xxx1  zz: xxx2  zz: xxx1  ;m
  1952. ;class
  1953.  
  1954. objPtr OO  class_is  xxx
  1955.  
  1956. xxx xxxx
  1957. qqq qqqq
  1958. xxxx -> oo
  1959.  
  1960. :class BLOGGS  super( object )
  1961.     var VV
  1962.     4    array AA
  1963. :m TEST:  db    2 +  i -  at: aa ;m
  1964. ;class
  1965.  
  1966. bloggs BB
  1967.  
  1968.  
  1969.  
  1970. :class MULT    super( var int array )
  1971.  
  1972. :m MTEST:    uget: super  999 1 to: self  ;m
  1973. :m MAT:        at: self  ;m
  1974. ;class
  1975.  
  1976. objPtr    OO    class_is mult
  1977. objPtr    OOO    class_is int
  1978.  
  1979. :class IVXX    super( object )
  1980.     10 bytes data2
  1981.     int    i1
  1982.     int    i2
  1983.     130 bytes qqqq        \ Include to check >128 distance
  1984.                 \  index addressing of array qwert
  1985.     9 array qwert
  1986.  
  1987. :m ITEST:
  1988.     get: i1  uget: i2  66 put: i2
  1989.     99 3 to: qwert  1234 drop  3 at: qwert
  1990.     addr: i2  ['] ooo !  ;m
  1991.  
  1992. :m GETQWERT:
  1993.     addr: qwert  ;m
  1994. ;class
  1995.  
  1996. int ii
  1997. 3 mult    mm
  1998. ivxx    iv
  1999.  
  2000. mm -> oo
  2001.  
  2002. itest: iv  . . .
  2003. mtest: mm  .
  2004. 88 iput: mm        \ Note: get: mm will bind to the var, but uget: mm
  2005.             \ will bind to the int and give 88.
  2006.  
  2007. \ A further test - Doug H found this bug:
  2008.  
  2009. :class  POINT    super{ object }
  2010.     int    Y        \ Vertical coordinate
  2011.     int    X        \ Horizontal  coordinate
  2012. ;class
  2013.  
  2014.  
  2015. :class  RECT  super{ object }
  2016.     point    TOPL
  2017.     point    BOTR
  2018. ;class
  2019.  
  2020. :class test1 super{ object }
  2021.  
  2022.     20 array a
  2023.  
  2024. :m classinit:
  2025.     55 0 to: a ;m
  2026.  
  2027. :m to:  to: a ;m
  2028.  
  2029. :m at:  at: a ;m
  2030.  
  2031. ;class
  2032.  
  2033. :class test3 super{ rect test1 }
  2034. :m classinit:
  2035.     [ 1 -> supers_to_skip ]  classinit: super
  2036. ;m
  2037. ;class
  2038.  
  2039. test3 t3
  2040.  
  2041.  
  2042. : q            db  getqwert: iv  3 swap at: **  ;        \ Should give 99
  2043. : qq        db 1 at: mm ;                            \ Should give 999
  2044. : qqq        db 1 mat: mm  ;                            \ Should give 999
  2045. : qqqq        db 1 mm at: mult  ;                        \ Should give 999
  2046. : z            db 1 mm at: **  ;                        \ Should give 999
  2047. : zz        db 1 mm at: array ;                        \ Should fail
  2048. : y            db 1 at: oo   ;                            \ Should give 999
  2049. : yy        db 1 mat: oo  ;                            \ Should give 999
  2050. : yyy        db uget: mm  ;                            \ Should optimize & give 88
  2051. : yyyy        db addr: mm  addr: oo  ;                \ Both numbers shd be same
  2052. : yyyyy        db uget: ooo  ;                            \ Should give 66
  2053. : yyyyyy    db  0 at: t3  ;                            \ Should give 55
  2054.  
  2055.  
  2056. : ?CHK    <> abort" check FAILED!!!"  ;
  2057.  
  2058. q         99    ?chk
  2059. qq         999    ?chk
  2060. qqq     999    ?chk
  2061. qqqq     999 ?chk
  2062. z         999    ?chk
  2063. y         999    ?chk
  2064. yy         999    ?chk
  2065. yyy     88    ?chk
  2066. yyyy        ?chk
  2067. yyyyy     66    ?chk
  2068. yyyyyy    55    ?chk
  2069.  
  2070. \ torture tests WORKED!  INCREDIBLE!!  CONGRATULATIONS!!!
  2071. \ (but remember to check that ZZ gives a "can't use indexed method" error)
  2072. key!
  2073.  
  2074. :class MULTX super( mult )
  2075. :m ntest:  db  444 1 to: super  ;m
  2076. ;class
  2077. 4 multx MX
  2078.  
  2079. \ ivar clash test
  2080.  
  2081. :class CLASH super( object )
  2082.  
  2083. 2 array A1
  2084. 3 array A2
  2085.  
  2086. :m TEST: db 77 1 to: a1  66 0 to: a2  1 at: a1  ;m    \ Shd give 77
  2087.  
  2088. ;class
  2089.  
  2090. clash CC
  2091.